package studiodiva.portfolio.client.view.viewer;

import static com.google.gwt.query.client.GQuery.$;
import static com.google.gwt.query.client.GQuery.$$;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.query.client.Function;
import com.google.gwt.query.client.Properties;
import com.google.gwt.query.client.css.CSS;
import com.google.gwt.query.client.css.Length;
import com.google.gwt.query.client.plugins.effects.PropertiesAnimation.Easing;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;

import static studiodiva.portfolio.client.lib.lang.Lang.doLater;
import static studiodiva.portfolio.client.lib.lang.Lang.is;

import studiodiva.portfolio.client.lib.even.EventFunction;
import studiodiva.portfolio.client.lib.lang.Run;
import studiodiva.portfolio.client.lib.view.View;
import studiodiva.portfolio.client.model.titles.Page;
import studiodiva.portfolio.client.model.titles.Title;

public class PageViewer extends View<Widget> {

  interface Binder extends UiBinder<Widget, PageViewer> {}

  static Binder uiBinder = GWT.create(Binder.class);

  private static final int LENGTH = 940;
  @UiField
  SimplePanel currentPanel;
  @UiField
  SimplePanel loadingPanel;
  private boolean loadAgain;
  private boolean loading;
  private int openIndex = -1;
  private TitlePageWidgetProvider pageProvider;

  public PageViewer() {
    initWidget(uiBinder.createAndBindUi(this));
  }

  public void close() {
    currentPanel.setWidget(null);
    openIndex = -1;
  }

  public void open(TitlePageWidgetProvider pageProvider) {
    this.pageProvider = pageProvider;
    openIndex = -1;
    showCurrentPage();
    registerReplaceByEvent(getTitle(), Title.ON_PAGE_CHANGE, new EventFunction<Page>() {
      public void run(Page value) {
        showCurrentPage();
      }
    });
  }

  private void animate(SimplePanel panel, final Runnable runnable) {
    $(panel).css(CSS.POSITION.with(Position.ABSOLUTE)).animate(getPanelAnimationProperties(),
        NORMAL_ANIMATION, Easing.SWING, new Function() {
          @Override
          public void f() {
            if (is(runnable)) runnable.run();
          }
        });
  }

  private Properties getPanelAnimationProperties() {
    if (isNextAnimation())
      return $$("left:'-=" + LENGTH + "',right:'+=" + LENGTH + "'");
    else return $$("left:'+=" + LENGTH + "',right:'-=" + LENGTH + "'");
  }

  private Title getTitle() {
    return pageProvider.getTitle();
  }

  private boolean isNextAnimation() {
    return getTitle().getCurrentIndex() >= openIndex;
  }

  private void setBeforeAnimationLoadingPanelPosition() {
    if (isNextAnimation()) {
      $(loadingPanel).css(CSS.LEFT.with(Length.px(LENGTH)));
      $(loadingPanel).css(CSS.RIGHT.with(Length.px(-LENGTH)));
    } else {
      $(loadingPanel).css(CSS.LEFT.with(Length.px(-LENGTH)));
      $(loadingPanel).css(CSS.RIGHT.with(Length.px(LENGTH)));
    }
  }

  private void showCurrentPage() {
    doLater(new Run() {
      public void run() {
        if (loading) {
          loadAgain = true;
          return;
        }
        loading = true;
        animate(currentPanel, null);
        loadingPanel.setWidget(pageProvider.createPageWidget());
        setBeforeAnimationLoadingPanelPosition();
        animate(loadingPanel, new Run() {
          public void run() {
            switchPanels();
            openIndex = getTitle().getCurrentIndex();
            loading = false;
            if (loadAgain) {
              loadAgain = false;
              showCurrentPage();
            }
          }
        });
      }
    });
  }

  private void switchPanels() {
    SimplePanel tmpCurrentPanel = currentPanel;
    currentPanel = loadingPanel;
    loadingPanel = tmpCurrentPanel;
  }
}
